This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1'use client'; 2 3import { useState, useEffect, useMemo, useCallback } from 'react'; 4import { useRouter, useParams } from 'next/navigation'; 5import { 6 Container, 7 Title, 8 TextInput, 9 Textarea, 10 Button, 11 Stack, 12 Card, 13 Group, 14 Alert, 15 LoadingOverlay, 16} from '@mantine/core'; 17import { getAccessToken } from '@/services/auth'; 18import { ApiClient } from '@/api-client/ApiClient'; 19import type { GetCollectionPageResponse } from '@/api-client/types'; 20 21export default function EditCollectionPage() { 22 const router = useRouter(); 23 const params = useParams(); 24 const collectionId = params.collectionId as string; 25 26 // Memoize API client to prevent recreation on every render 27 const apiClient = useMemo( 28 () => 29 new ApiClient( 30 process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3000', 31 () => getAccessToken(), 32 ), 33 [], 34 ); 35 36 const [collection, setCollection] = 37 useState<GetCollectionPageResponse | null>(null); 38 const [name, setName] = useState(''); 39 const [description, setDescription] = useState(''); 40 const [isLoading, setIsLoading] = useState(true); 41 const [isSaving, setIsSaving] = useState(false); 42 const [error, setError] = useState<string | null>(null); 43 const [success, setSuccess] = useState(false); 44 45 // Memoize the load collection function to prevent recreation 46 const loadCollection = useCallback(async () => { 47 if (!collectionId) return; 48 49 try { 50 setIsLoading(true); 51 setError(null); 52 const response = await apiClient.getCollectionPage(collectionId); 53 setCollection(response); 54 setName(response.name); 55 setDescription(response.description || ''); 56 } catch (err) { 57 setError('Failed to load collection'); 58 console.error('Error loading collection:', err); 59 } finally { 60 setIsLoading(false); 61 } 62 }, [collectionId, apiClient]); 63 64 // Load collection data 65 useEffect(() => { 66 loadCollection(); 67 }, [loadCollection]); 68 69 const handleSave = useCallback(async () => { 70 if (!name.trim()) { 71 setError('Collection name is required'); 72 return; 73 } 74 75 try { 76 setIsSaving(true); 77 setError(null); 78 79 await apiClient.updateCollection({ 80 collectionId, 81 name: name.trim(), 82 description: description.trim() || undefined, 83 }); 84 85 setSuccess(true); 86 87 // Redirect back to collection page after a brief delay 88 setTimeout(() => { 89 router.push(`/collections/${collectionId}`); 90 }, 1500); 91 } catch (err) { 92 setError('Failed to update collection'); 93 console.error('Error updating collection:', err); 94 } finally { 95 setIsSaving(false); 96 } 97 }, [name, description, collectionId, apiClient, router]); 98 99 const handleCancel = useCallback(() => { 100 router.push(`/collections/${collectionId}`); 101 }, [router, collectionId]); 102 103 if (isLoading) { 104 return ( 105 <Container size="md" py="xl"> 106 <LoadingOverlay visible /> 107 </Container> 108 ); 109 } 110 111 if (!collection) { 112 return ( 113 <Container size="md" py="xl"> 114 <Alert color="red" title="Collection not found" /> 115 </Container> 116 ); 117 } 118 119 return ( 120 <Container size="md" py="xl"> 121 <Stack gap="lg"> 122 <Title order={1}>Edit Collection</Title> 123 124 <Card withBorder p="lg"> 125 <Stack gap="md"> 126 {error && <Alert color="red" title={error} />} 127 128 {success && ( 129 <Alert color="green" title="Collection updated successfully! Redirecting..." /> 130 )} 131 132 <TextInput 133 label="Collection Name" 134 placeholder="Enter collection name" 135 value={name} 136 onChange={(event) => setName(event.currentTarget.value)} 137 required 138 error={!name.trim() && error ? 'Name is required' : undefined} 139 /> 140 141 <Textarea 142 label="Description" 143 placeholder="Enter collection description (optional)" 144 value={description} 145 onChange={(event) => setDescription(event.currentTarget.value)} 146 minRows={3} 147 maxRows={6} 148 /> 149 150 <Group justify="flex-end" mt="md"> 151 <Button 152 variant="subtle" 153 onClick={handleCancel} 154 disabled={isSaving} 155 > 156 Cancel 157 </Button> 158 <Button 159 onClick={handleSave} 160 loading={isSaving} 161 disabled={!name.trim() || success} 162 > 163 Save Changes 164 </Button> 165 </Group> 166 </Stack> 167 </Card> 168 </Stack> 169 </Container> 170 ); 171}